<?php
/**
 * @link https://www.len168.com
 * @copyright Copyright (c) 2020/9/21 len168.com
 * @author toshcn <toshcn@foxmail.com>
 */

namespace common\components\sms;

use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Client\Exception\ClientException;
use AlibabaCloud\Client\Exception\ServerException;
use phpDocumentor\Reflection\DocBlock\Tags\Var_;
use Yii;
use yii\db\Query;

// Download：https://github.com/aliyun/openapi-sdk-php
// Usage：https://github.com/aliyun/openapi-sdk-php/blob/master/README.md
class AliyunSms extends DefaultSms implements SmsInterface
{
    // [阿里云短信相关参数配置](https://help.aliyun.com/document_detail/101300.html?spm=a2c4g.11186623.6.610.48813e2cQDkci4)
    public $accessKeyId = '';
    public $accessSecret = '';
    public $regionId = 'cn-hangzhou';
    public $product = 'Dysmsapi';
    public $scheme = 'https';// https|http
    public $templateType = 'aliyun';
    public $version = '2017-05-25';
    public $host = 'dysmsapi.aliyuncs.com';

    public $db = 'db';
    /**
     * @var string 短信模板表.
     */
    public $smsTable = '{{%sms_tpl}}';

    /**
     * 初始化
     */
    public function init()
    {
        parent::init();
        $sms = Yii::$app->config->getSiteItem('aliyunSms');
        $this->accessKeyId = isset($sms['key']) ? trim($sms['key']) : '';
        $this->accessSecret = isset($sms['secret']) ? trim($sms['secret']) : '';
        $db = $this->db;
        $this->db = Yii::$app->$db;
    }

    /**
     * 生成单个发送短信接口需要的格式
     * @param number $country [国家或地区码]
     * @param number $phone [手机号]
     * @param string $label 短信模板标签
     * @param array $param 短信模板变量数组
     * @return array|mixed
     * @throws \yii\db\Exception
     */
    public function formatData($country, $phone, $label, $param = [])
    {
        $tpl = $this->querySmsTemplate($this->templateType, $label);
        $templateParam = json_decode($tpl['tpl_param'], true);
        $smsParam = [];
        if (is_array($templateParam)){
            foreach ($templateParam as $key => $item) {
                $smsParam[$key] = isset($param[$item]) ? $param[$item] : '';
            }
        }
        return [
            'PhoneNumbers' => $country == 86 ? $phone : $country . $phone,
            'SignName' => $tpl['tpl_sign'],
            'TemplateCode' => $tpl['tpl_code'],
            'TemplateParam' => json_encode($smsParam)
        ];
    }

    /**
     * 生成批量发送短信接口需要的格式
     * @param array $country [国家或地区码]
     * @param array $phones [手机号]]
     * @param string $label 短信模板标签
     * @param array $param 短信模板变量数组
     * @return array|mixed
     * @throws \yii\db\Exception
     */
    public function formatBatchData($country, $phones, $label, $param = [])
    {
        $tpl = $this->querySmsTemplate($this->templateType, $label);
        $templateParam = json_decode($tpl['tpl_param'], true);
        $smsParam = [];
        if (is_array($templateParam)){
            foreach ($templateParam as $key => $item) {
                $smsParam[$key] = isset($param[$item]) ? $param[$item] : '';
            }
        }
        $phoneNumberJson = [];
        $signNameJson = [];
        $templateParamJson = [];

        foreach ($phones as $key => $phone) {
            $signNameJson[] = $tpl['tpl_sign'];
            $templateParamJson[] = $smsParam;
            $phoneNumberJson[] = $country[$key] == 86 ? $phone : $country . $phone;
        }
        return [
            'PhoneNumberJson' => json_encode($phoneNumberJson),
            'SignNameJson' => json_encode($signNameJson),
            'TemplateCode' => $tpl['tpl_code'],
            'TemplateParamJson' => json_encode($templateParamJson)
        ];
    }

    /**
     * 通过模板类型，模板签名查询模板
     * @param string $type 模板类型
     * @param string $label 模板标签名
     * @return false|null|array
     * @throws \yii\db\Exception
     */
    protected function querySmsTemplate($type, $label)
    {
        $key = Yii::$app->util->cacheKey("{$type}_{$label}");
        $result = Yii::$app->getCache()->get($key);
        if ($result === false) {
            $query = new Query();
            $query->select('*')
                ->from($this->smsTable)
                ->where('[[tpl_type]] = :type AND [[tpl_label]] = :label', [':type' => $type, ':label' => $label]);
            $result = $query->createCommand($this->db)->queryOne();
            Yii::$app->getCache()->set($key, $result);
        }

        return $result;
    }

    /**
     * 单个发送短信
     * @param array $data
     * $data['PhoneNumbers'] 手机号，[国家或地区码][手机号]
     * $data['SignName'] 短信签名名称
     * $data['TemplateCode'] 短信模板ID
     * $data['TemplateParam'] 短信模板变量对应的实际值，JSON格式。{"code":"1111"}
     * @return array
     * @throws ClientException|ServerException
     */
    public function sendData($data)
    {
        AlibabaCloud::accessKeyClient($this->accessKeyId, $this->accessSecret)
            ->regionId($this->regionId)
            ->asDefaultClient();
        try {
            $result = AlibabaCloud::rpc()
                ->product($this->product)
                ->scheme($this->scheme)// https | http
                ->version($this->version)
                ->action('SendSms')
                ->method('POST')
                ->host($this->host)
                ->options([
                    'query' => [
                        'RegionId' => $this->regionId,
                        'PhoneNumbers' => trim($data['PhoneNumbers']),
                        'SignName' => trim($data['SignName']),
                        'TemplateCode' => trim($data['TemplateCode']),
                        'TemplateParam' => $data['TemplateParam']
                    ]
                ])
                ->request();
            $info = $result->toArray();
            if (isset($info['Code']) && $info['Code'] == 'OK') {
                return ['code' => 1, 'message' => 'success'];
            }
            return ['code' => 0, 'message' => isset($info['Message']) ? $info['Message'] : 'error'];
        } catch (ClientException $e) {
            return ['code' => 0, 'message' => $e->getErrorMessage()];
        } catch (ServerException $e) {
            return ['code' => 0, 'message' => $e->getErrorMessage()];
        }
    }

    /**
     * 批量发送短信
     * @param array $data
     * $data['PhoneNumberJson'] 接收短信的手机号码，JSON数组格式，["15900000000","13500000000"]
     * $data['SignNameJson'] 短信签名名称，JSON数组格式 ["阿里云","阿里巴巴"]
     * $data['TemplateCode'] 短信模板CODE
     * $data['TemplateParamJson'] 短信模板变量对应的实际值，JSON格式。[{"name":"TemplateParamJson"},{"name":"TemplateParamJson"}]
     * @return array
     * @throws ClientException|ServerException
     */
    public function sendBatchData($data)
    {
        AlibabaCloud::accessKeyClient($this->accessKeyId, $this->accessSecret)
            ->regionId($this->regionId)
            ->asDefaultClient();
        try {
            $result = AlibabaCloud::rpc()
                ->product($this->product)
                ->scheme($this->scheme)// https | http
                ->version($this->version)
                ->action('SendBatchSms')
                ->method('POST')
                ->host($this->host)
                ->options([
                    'query' => [
                        'RegionId' => $this->regionId,
                        'PhoneNumberJson' => $data['PhoneNumberJson'],
                        'SignNameJson' => $data['SignNameJson'],
                        'TemplateCode' => $data['TemplateCode'],
                        'TemplateParamJson' => $data['TemplateParamJson']
                    ]
                ])
                ->request();
            $info = $result->toArray();
            if (isset($info['Code']) && $info['Code'] == 'OK') {
                return ['code' => 1, 'message' => 'success'];
            }
            return ['code' => 0, 'message' => isset($info['Message']) ? $info['Message'] : 'error'];
        } catch (ClientException $e) {
            return ['code' => 0, 'message' => $e->getErrorMessage()];
        } catch (ServerException $e) {
            return ['code' => 0, 'message' => $e->getErrorMessage()];
        }
    }
}
